﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using log4net;
using MarketData;
using News;
using Snap.Model;

namespace Snap.Driver
{
	public class Driver
	{
        private static readonly ILog Logger =
            LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        private static readonly Stopwatch StopWatch = new Stopwatch();

		
	    static void Main()
        {
            Logger.Info( Environment.NewLine );
            Logger.Info( "Starting SNAP Driver..." );
            Logger.Info( "Pulling RSS Feeds..." );
            NewsUpdater.PullRssFeeds();
            Logger.Info( "Pulling Market Data..." );
            PullMarketData();
            Logger.Info( "Finished SNAP Driver." );
        }

	    #region Market Data

        private static void PullMarketData()
        {
            // Get DB context
            var contextForMapping = new SnapModelContainer();
            var todayMidnight = DateTime.UtcNow.Date;
            var symbolToNewsGroup = contextForMapping.NewsToCompanies
                .Where( ntc => (ntc.NewsItem.PublicationDate < todayMidnight) )
                .GroupBy( ntc => ntc.CompanySymbol, ntc => ntc.NewsItem )
                .Select( g => new {Symbol = g.Key, NewsItems = g} )
                .ToList();

            var tpAdapter = new TradingPhysicsAdapter( Properties.Settings.Default.TPCustomerNumber,
        	                                           Properties.Settings.Default.TPPasswordHash,
        	                                           Properties.Settings.Default.TPServerUrl );
        	// Pull all needed market data
            StopWatch.Restart();
            int numberOfTotalTickers = 0;
            foreach (var group in symbolToNewsGroup)
            {
                int numberOfInternalTickers = 0;
                var contextForTickers = new SnapModelContainer();
                var uniqueDates = group.NewsItems.Select( ni => ni.PublicationDate.Date ).Distinct().ToList();
                foreach (var date in uniqueDates)
                {
                    var tickers = new List<Ticker>();
                    var justTheDate = date.Date;
                    var justTheNextDate = justTheDate.AddDays( 1 );
                    var currentSymbol = group.Symbol;
                    if (contextForMapping.Tickers.Where( t => t.CompanySymbol == currentSymbol &&
                                                              t.MarketDate >= justTheDate &&
                                                              t.MarketDate < justTheNextDate ).Any())
                    {
                        // We've already pulled market data for this symbol on this day.
                        continue;
                    }
                    Logger.DebugFormat( "Pulling market data for {0} from {1:MMddyyyy}...", currentSymbol, justTheDate );
                    tickers.AddRange( tpAdapter.GetTickIndicators( group.Symbol, date,
                                                               Properties.Settings.Default.TickLengthMilliseconds ) );
                    numberOfInternalTickers += tickers.Count;

                    // To save space, the Market Data provider passes in a zero if the price is unchanged since last tick.
                    // We want to store this with the previous price instead.
                    // If first price is zero, use OpenPrice
                    var googleFinanceAdapter = new GoogleFinanceAdapter();
                    decimal openPrice = googleFinanceAdapter.GetOpeningPrice( group.Symbol, date );
                    if (tickers.Count > 0)
                    {
                        if (tickers[0].BuyPriceAvg == 0.0m)
                        {
                            tickers[0].BuyPriceAvg = openPrice;    
                        }
                        if (tickers[0].SellPriceAvg == 0.0m)
                        {
                            tickers[0].SellPriceAvg = openPrice;
                        }
                        
                    }
                    int numberOfTickers = tickers.Count;
                    for (int i = 0; i < numberOfTickers; i++)
                    {
                        if (tickers[i].BuyPriceAvg == 0.0m && i > 0)
                        {
                            // Zero means unchanged price; assign the previous price to this.
                            tickers[i].BuyPriceAvg = tickers[i - 1].BuyPriceAvg;
                        }
                        if(tickers[i].SellPriceAvg == 0.0m && i > 0)
                        {
                            tickers[i].SellPriceAvg = tickers[i - 1].SellPriceAvg;
                        }
                    }

                    foreach (var ticker in tickers)
                    {
                        contextForTickers.Tickers.AddObject( ticker );
                    }
                }
                numberOfTotalTickers += numberOfInternalTickers;
                Logger.DebugFormat( "Storing {0} tickers for {1}", numberOfInternalTickers, group.Symbol );
                StopWatch.Restart();
                contextForTickers.SaveChanges();
                StopWatch.Stop();
                Logger.DebugFormat( "Finished storing tickers. Duration: {0} ({1}/second)", StopWatch.Elapsed,
                                    (numberOfInternalTickers / StopWatch.Elapsed.TotalSeconds) );
            }
            StopWatch.Stop();
            Logger.InfoFormat( "Pulled and stored {0} sets of tickers in {1}.", numberOfTotalTickers, StopWatch.Elapsed );

            
            Logger.Debug( "Finished pulling tickers." );
        }

        #endregion Market Data
    }
}
